package com.zj.netty.server;

import com.zj.netty.utils.Constant;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class ServerNetty {
    private int port;
    public ServerNetty(int port){
        this.port = port;
    }

    // netty 服务端启动
    public void start() throws InterruptedException{

        /*首先我们创建了两个NioEventLoopGroup实例，它是一个由Netty封装好的包含NIO的线程组。
        为什么创建两个？因为Netty的底层是IO多路复用，bossGroup 是用于接收客户端的连接，
        原理就是一个实现的Selector的Reactor线程。而workerGroup用于进行SocketChannel的网络读写。*/
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // Netty的入口，通过这类来启动Netty，:ServerBootstrap负责初始化netty服务器，并且开始监听端口的socket请求
            ServerBootstrap sbs = new ServerBootstrap();
            // 将两个NioEventLoopGroup实例绑定到ServerBootstrap对象中
            sbs.group(bossGroup, workerGroup)
                /** 创建Channel（典型的channel有NioSocketChannel，NioServerSocketChannel，OioSocketChannel，OioServerSocketChannel，
                 *  EpollSocketChannel，EpollServerSocketChannel），这里创建的是NIOserverSocketChannel，
                 *  它的功能可以理解为当接受到客户端的连接请求的时候，完成TCP三次握手，TCP物理链路建立成功。
                 *  并将该“通道”与workerGroup线程组的某个线程相关联。
                 */
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024) // 设置参数，这里设置的SO_BACKLOG，意思是客户端连接等待队列的长度为1024.
                    .childOption(ChannelOption.SO_KEEPALIVE, true) //保持连接
                    .handler(new LoggingHandler(LogLevel.INFO)) // 打印日志级别
                    //建立连接后的具体Handler。就是我们接受数据后的具体操作，例如：记录日志，对信息解码编码等
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                        // 处理接收到的请求，为监听客户端read/write事件的Channel添加用户自定义的ChannelHandler
                        socketChannel.pipeline().addLast(new ServerHandler());
                        }
                    });

            System.err.println("server 开启--------------");
            // 绑定端口，开始接受链接
            ChannelFuture cf = sbs.bind(port).sync();

            // 等待服务端口的关闭；优雅实现关闭服务
            cf.channel().closeFuture().sync();
        } finally{
            // 优雅退出，释放线程池资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    // 开启netty服务线程
    public static void main(String[] args) throws InterruptedException {
        new ServerNetty(Constant.serverSocketPort).start();
    }
}
